package com.corpgovernment.organization.service.budget;

import com.corpgovernment.api.organization.bo.budget.BaseBudgetRequestBO;
import com.corpgovernment.api.organization.bo.budget.BaseBudgetResponseBO;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.redis.handler.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.UUID;

@Slf4j
public abstract class BaseBudgetService<Q extends BaseBudgetRequestBO, P extends BaseBudgetResponseBO> {

    /**
     * 锁前缀
     */
    private static final String BUDGET_REDIS_KEY = "BUDGET_";

    /**
     * 默认锁定时间
     */
    private static final Long BUDGET_REDIS_SECONDS = 20L;

    @Autowired
    private RedisLock redisLock;

    public final P handleRequest(Q baseRequest) {
        String value = UUID.randomUUID().toString();
        try {
            if (!acquireLock(baseRequest, value)) {
                log.info(String.format("预算单[%s]获取Redis锁失败", baseRequest.getBudgetId()));
                throw new CorpBusinessException(OrganizationResponseCodeEnum.USER_BUDGET_OCCUPY);
            }
            return doOperation(baseRequest);
        } finally {
            releaseLock(baseRequest, value);
        }
    }

    protected boolean acquireLock(BaseBudgetRequestBO baseRequest, String value) {
        String key = generateRedisLockKey(baseRequest);
        return redisLock.lock(key, value, BUDGET_REDIS_SECONDS);
    }

    protected void releaseLock(BaseBudgetRequestBO baseRequest, String value) {
        String key = generateRedisLockKey(baseRequest);
        redisLock.unlock(key, value);
    }

    private String generateRedisLockKey(BaseBudgetRequestBO baseRequest) {
        return BUDGET_REDIS_KEY + baseRequest.getBudgetId();
    }

    public abstract P doOperation(Q baseRequest);
}